
#include <iostream>
#include <fstream>
#include <vector>

#include "pb_cfg_shop.pb.h"
#include "MsgShop.pb.h"
#include "commmsg.h"
#include "../mainctrl.h"
#include "../equip/CEquipMgr.h"
#include "../storage/CStorageMgr.h"
#include "../item/CItemMgr.h"
#include "../clan/CClanMgr.h"
#include "../act/CActMgr.h"
#include "../data/CPlayerOnlineData.h"
#include "CShopMgr.h"
#include "CUserShop.h"

//初始化用户商店
int CShopMgr::InitData(CUserShop & stUserShop, CShopData & stShopData)
{
    stUserShop.Clear();

    stUserShop._stMysticalShop._ucCaneCnt = stShopData._ucCaneCnt;
    stUserShop._stMysticalShop._ucGoldRefreshCnt = stShopData._ucGoldRefreshCnt;
    for (int i = 0; i < stShopData._astShopItem.Size(); i++)
    {
        if (0 == stShopData._astShopItem[i]._ucItemType)
        {
            continue;
        }

        int iSilverPrices = 0;
        int iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetItemPrice(stShopData._astShopItem[i]._ucItemType,
            stShopData._astShopItem[i]._usItemID, stShopData._astShopItem[i]._usItemCnt,
            ITEM_BUY_PRICE_SILVER, iSilverPrices);
        if (iRet)
        {
            CT_ERROR(("%d, %d, %d", stShopData._astShopItem[i]._ucItemType, stShopData._astShopItem[i]._usItemID, iRet));
            return ERROR_SHOP_MYSTICAL_CONFIG;
        }

        CShopItemConfig stShopItem;
        stShopItem._ucItemType = stShopData._astShopItem[i]._ucItemType;
        stShopItem._usItemConfigID = stShopData._astShopItem[i]._usItemID;
        stShopItem._usItemCount = stShopData._astShopItem[i]._usItemCnt;
        stShopItem._ucBuyType = ITEM_TYPE_SILVER;
        stShopItem._ucExchangeItemType = ITEM_TYPE_SILVER;
        stShopItem._iExchangeItemCount = iSilverPrices;
        if (true == stShopData._astShopItem[i]._ucIsSaleOut)
        {
            stShopItem._usExchangeItemID = SHOP_ITEM_SALE_OUT;
        }

        stUserShop._stMysticalShop._astShopItem.AddOneItem(stShopItem);
    }

    stUserShop._stMysticalShop._iRenewCaneTime = stShopData._iRenewCaneTime;
    stUserShop._stMysticalShop._iClearCntTime = stShopData._iClearCntTime;

    stUserShop._stClanShop._iLastBuyTime = stShopData._iLastBuyTime;
    for (int i = 0; i < stShopData._astBuyItems.Size(); i++)
    {
        stUserShop._stClanShop._astBuyItems.AddOneItem(stShopData._astBuyItems[i]);
    }

    stUserShop._iClearCrystalShopTime = stShopData._iClearCrystalShopTime;
    for (int i = 0; i < stShopData._astCrystalItems.Size(); i++)
    {
        stUserShop._astCrystalItems.AddOneItem(stShopData._astCrystalItems[i]);
    }

    return 0;
}

void CShopMgr::GetData(CUserShop & stUserShop, CShopData & stShopData)
{
    stShopData.Clear();

    stShopData._ucCaneCnt = stUserShop._stMysticalShop._ucCaneCnt;
    stShopData._ucGoldRefreshCnt = stUserShop._stMysticalShop._ucGoldRefreshCnt;
    for (int i = 0; i < stUserShop._stMysticalShop._astShopItem.Size(); i++)
    {
        CShopItemData stShopItem = stShopData._astShopItem[i];
        stShopItem._ucItemType = stUserShop._stMysticalShop._astShopItem[i]._ucItemType;
        stShopItem._usItemID = stUserShop._stMysticalShop._astShopItem[i]._usItemConfigID;
        stShopItem._usItemCnt = stUserShop._stMysticalShop._astShopItem[i]._usItemCount;

        if (SHOP_ITEM_SALE_OUT == stUserShop._stMysticalShop._astShopItem[i]._usExchangeItemID)
        {
            stShopItem._ucIsSaleOut = true;
        }
        else
        {
            stShopItem._ucIsSaleOut = false;
        }

        stShopData._astShopItem.AddOneItem(stShopItem);
    }

    stShopData._iRenewCaneTime = stUserShop._stMysticalShop._iRenewCaneTime;
    stShopData._iClearCntTime = stUserShop._stMysticalShop._iClearCntTime;

    stShopData._iLastBuyTime = stUserShop._stClanShop._iLastBuyTime;
    for (int i = 0; i < stUserShop._stClanShop._astBuyItems.Size(); i++)
    {
        stShopData._astBuyItems.AddOneItem(stUserShop._stClanShop._astBuyItems[i]);
    }

    stShopData._iClearCrystalShopTime = stUserShop._iClearCrystalShopTime;
    for (int i = 0; i < stUserShop._astCrystalItems.Size(); i++)
    {
        stShopData._astCrystalItems.AddOneItem(stUserShop._astCrystalItems[i]);
    }
}

int CShopMgr::InitMysticalShop (unsigned int uiGid, CUserShop & stUserShop, int iNowTime, CShopData & stShopData)
{
    stUserShop._stMysticalShop.Clear();
    int iCaneCDTime = 0;

    int iRet = GetCanCdTime(uiGid, iCaneCDTime);
    CHECK_RETURN(iRet);

    stUserShop._stMysticalShop._ucCaneCnt = 1;   //TASK #263::神秘商店默认给用户一次刷新资格
    stUserShop._stMysticalShop._iRenewCaneTime = iNowTime + iCaneCDTime;
    stUserShop._stMysticalShop._iClearCntTime = iNowTime + (MYSTICAL_CLEAR_REFRESH_TIME - iNowTime % MYSTICAL_CLEAR_REFRESH_TIME);

    iRet = RefreshShopItem(uiGid, stUserShop, 1, MYSTICAL_UPDATE_CANE);
    CHECK_RETURN(iRet);

    GetData(stUserShop, stShopData);
    return 0;
}

//读取配置
int CShopMgr::LoadConfig(const char* szCfgPath)
{
    int iRet = 0;

    if (szCfgPath == NULL)
    {
        CT_ERROR(("Item Cfg Path is null"));
        return RET_SYSTEM_FAIL;
    }

    pb_cfg_shop stShopPBConfig;
    std::fstream stFileInput(szCfgPath, std::ios::in | std::ios::binary);
    if (!stShopPBConfig.ParseFromIstream(&stFileInput))
    {
        CT_ERROR(("Failed to Parse stShopPBConfig! %s", szCfgPath));
        return RET_SYSTEM_FAIL;
    }

    for (int i = 0; i < stShopPBConfig.shop_id_rows_size(); ++i)
    {
        const pb_cfg_shop_pb_cfg_shop_id_unit & stRoleShopIdConfigUnit
            = stShopPBConfig.shop_id_rows(i);

        CRoleToShopId  stConfigData;
        stConfigData._sRoleLevel = stRoleShopIdConfigUnit.level();
        stConfigData._ucNearByShopId = stRoleShopIdConfigUnit.nearby_shop_id();
        stConfigData._ucMysticalShopId = stRoleShopIdConfigUnit.mystical_shop_id();
        stConfigData._ucClanShopId = stRoleShopIdConfigUnit.clan_shop_id();
        stConfigData._iCaneCDTime = stRoleShopIdConfigUnit.cane_cd_time();

        iRet = _stRoleToShopId.AddConfig(stConfigData);
        if (iRet)
        {
            CT_ERROR((""));
            return iRet;
        }
    }

    for (int i = 0; i < stShopPBConfig.near_by_shop_rows_size(); ++i)
    {
        const pb_cfg_shop_pb_cfg_near_by_shop_unit& stNearByShopPBConfigUnit
            = stShopPBConfig.near_by_shop_rows(i);

        CShopItemConfig stConfigData;
        unsigned char ucNearByShopId = (unsigned char)(stNearByShopPBConfigUnit.nearby_shop_id() & 0x7F);
        stConfigData._ucItemType = (unsigned char)(stNearByShopPBConfigUnit.item_type() & 0x7F);
        stConfigData._usItemConfigID = (unsigned short)(stNearByShopPBConfigUnit.item_id() & 0x7FFF);
        stConfigData._usItemCount = (unsigned short)(stNearByShopPBConfigUnit.item_count() & 0x7FFF);

        stConfigData._usDiscount = (unsigned short)(stNearByShopPBConfigUnit.discount() & 0x7FFF);
        stConfigData._ucBuyType = (unsigned char)(stNearByShopPBConfigUnit.buy_type() & 0x7F);

        int iPrice;
        EN_ITEM_PRICE_TYPE enPriceType;
        switch (stConfigData._ucBuyType)
        {
        case ITEM_TYPE_GOLD:
            {
                enPriceType = ITEM_BUY_PRICE_GOLD;
                stConfigData._ucExchangeItemType = ITEM_TYPE_GOLD;
            }
            break;

        case ITEM_TYPE_SILVER:
            {
                enPriceType = ITEM_BUY_PRICE_SILVER;
                stConfigData._ucExchangeItemType = ITEM_TYPE_SILVER;
            }
            break;

        default:
            return ERROR_SHOP_NEARBY_CONFIG;
        }

        iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetItemPrice(stConfigData._ucItemType, stConfigData._usItemConfigID,
            stConfigData._usItemCount, enPriceType, iPrice);
        if (iRet)
        {
            CT_ERROR(("%d, %d, %d, %d", stConfigData._ucItemType, stConfigData._usItemConfigID, stConfigData._usItemCount));
            return iRet;
        }

        stConfigData._iExchangeItemCount = iPrice;
        iRet = _stNearByShopConfig.AddConfigData(ucNearByShopId, stConfigData);
        CHECK_RETURN(iRet);
    }

    for (int i = 0; i < stShopPBConfig.equip_shop_rows_size(); ++i)
    {
        const pb_cfg_shop_pb_cfg_equip_shop_unit & stEquipShopPBConfigUnit
            = stShopPBConfig.equip_shop_rows(i);

        CShopItemConfig stConfigData;
        stConfigData._ucItemType = (unsigned char)(stEquipShopPBConfigUnit.item_type() & 0x7F);
        stConfigData._usItemConfigID = (unsigned short)(stEquipShopPBConfigUnit.item_id() & 0x7FFF);
        stConfigData._usItemCount = (unsigned short)(stEquipShopPBConfigUnit.item_count() & 0x7FFF);

        stConfigData._usDiscount = (unsigned short)(stEquipShopPBConfigUnit.discount() & 0x7FFF);
        stConfigData._ucBuyType = (unsigned char)(stEquipShopPBConfigUnit.buy_type() & 0x7F);
        if (ITEM_TYPE_SILVER != stConfigData._ucBuyType)
        {
            return ERROR_EQUIP_SHOP_CONFIG;
        }

        int iPrice;
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetItemPrice(stConfigData._ucItemType, stConfigData._usItemConfigID,
            stConfigData._usItemCount, ITEM_BUY_PRICE_SILVER, iPrice);
        if (iRet)
        {
            CT_ERROR(("%d, %d, %d, %d", stConfigData._ucItemType, stConfigData._usItemConfigID, stConfigData._usItemCount));
            return iRet;
        }

        stConfigData._ucExchangeItemType = ITEM_TYPE_SILVER;
        stConfigData._iExchangeItemCount = iPrice;
        iRet = _stEquipShopConfig.AddConfigData(stConfigData);
        CHECK_RETURN(iRet);
    }

    for (int i = 0; i < stShopPBConfig.mystical_shop_rows_size(); ++i)
    {
        const pb_cfg_shop_pb_cfg_mystical_shop_unit & stMysticalShopPBConfigUnit
            = stShopPBConfig.mystical_shop_rows(i);

        unsigned char ucMysticalShopId = (unsigned char)(stMysticalShopPBConfigUnit.mystical_shop_id() & 0x7F);
        CMysticalShopItemConfig stItemConfig;
        stItemConfig._ucShopItemType = (unsigned char)(stMysticalShopPBConfigUnit.item_type() & 0x7F);
        stItemConfig._ucShopCount = (unsigned char)(stMysticalShopPBConfigUnit.count() & 0x7F);
        stItemConfig._usConfigId = stMysticalShopPBConfigUnit.item_id();
        stItemConfig._szShopItemSubType.Set("%s", stMysticalShopPBConfigUnit.subtype().c_str());

        //判断配置是否有效
        if (stItemConfig._usConfigId == 0)
        {
            CDropItemData stData;
            iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetDropItemDataByKey(stItemConfig._ucShopItemType, stItemConfig._szShopItemSubType(), stItemConfig._ucShopCount, stData);
            if (iRet)
            {
                CT_ERROR(("%d, %d, %s, %d", ucMysticalShopId, stItemConfig._ucShopItemType, stItemConfig._szShopItemSubType(), iRet));
                return iRet;
            }
        }
        else
        {
            int iPrices = 0;
            iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetItemPrice(stItemConfig._ucShopItemType, stItemConfig._usConfigId, 1,
                ITEM_BUY_PRICE_SILVER, iPrices);
            if (iRet)
            {
                CT_ERROR(("%d, %d, %d, %d", ucMysticalShopId, stItemConfig._ucShopItemType, stItemConfig._usConfigId, iRet));
                return iRet;
            }
        }

        unsigned char ucPos;
        iRet = _stMystShopConfig.AddConfigData(ucMysticalShopId, stItemConfig, ucPos);
        if (iRet)
        {
            CT_ERROR(("%d, %d, %s, %d", ucMysticalShopId, stItemConfig._ucShopItemType, stItemConfig._szShopItemSubType(), iRet));
            return iRet;
        }

        _stMystShopConfig._stMystItemDrop.AddDropData(ucMysticalShopId, ucPos, MYSTICAL_UPDATE_GOLD, stMysticalShopPBConfigUnit.noramal_rate());
        _stMystShopConfig._stMystItemDrop.AddDropData(ucMysticalShopId, ucPos, MYSTICAL_UPDATE_CANE, stMysticalShopPBConfigUnit.gold_rate());
    }

    for (int i = 0; i < stShopPBConfig.clan_shop_rows_size(); ++i)
    {
        const pb_cfg_shop_pb_cfg_clan_shop_unit & stClanShopPBConfigUnit
            = stShopPBConfig.clan_shop_rows(i);

        unsigned char ucClanShopId = (unsigned char)(stClanShopPBConfigUnit.clan_shop_id() & 0x7F);
        CClanShopItemConfig stItemConfig;
        stItemConfig._ucShopItemType = (unsigned char)(stClanShopPBConfigUnit.item_type() & 0x7F);
        stItemConfig._ucShopCount = (unsigned char)(stClanShopPBConfigUnit.count() & 0x7F);
        stItemConfig._usItemConfigId = stClanShopPBConfigUnit.item_id();
        stItemConfig._szShopItemSubType.Set("%s", stClanShopPBConfigUnit.subtype().c_str());

        unsigned char ucPos;
        iRet = _stClanShopConfig.AddConfigData(ucClanShopId, stItemConfig, ucPos);
        if (iRet)
        {
            CT_ERROR(("%d, %d, %s, %d", ucClanShopId, stItemConfig._ucShopItemType, stItemConfig._szShopItemSubType(), iRet));
            return iRet;
        }

        iRet = _stClanShopConfig._stClanItemDrop.AddDropData(ucClanShopId, ucPos, stClanShopPBConfigUnit.drop_rate());
        if (iRet)
        {
            CT_ERROR (("%d, %d, %d", ucClanShopId, ucPos, stClanShopPBConfigUnit.drop_rate()));
            return iRet;
        }
    }

    for (int i = 0; i < stShopPBConfig.crystal_shop_rows_size(); ++i)
    {
        const pb_cfg_shop_pb_cfg_crystal_shop_unit & stCrystalShopPBConfigUnit
            = stShopPBConfig.crystal_shop_rows(i);

        CCrystalShopItemConfig stItemConfig;
        stItemConfig._ucItemType = stCrystalShopPBConfigUnit.item_type();
        stItemConfig._usItemId = stCrystalShopPBConfigUnit.item_id();
        stItemConfig._iItemCount = stCrystalShopPBConfigUnit.item_count();
        stItemConfig._iSealCost = stCrystalShopPBConfigUnit.seal_cnt();
        stItemConfig._iGoldCost = stCrystalShopPBConfigUnit.gold_cnt();

        iRet = _stCrystalShopConfig.AddConfigData(stItemConfig);
        if (iRet)
        {
            CT_ERROR(("%d, %d, %d, %d, %d ",stItemConfig._ucItemType, stItemConfig._usItemId, stItemConfig._iItemCount,
                stItemConfig._iSealCost, stItemConfig._iGoldCost));
            return iRet;
        }
    }

    return 0;
}

//更新神秘商店中物品
int CShopMgr::RefreshShopItem(unsigned int uiGid, CUserShop & stUserShop, short sPlayerLevel, unsigned char ucUpdateType)
{
    unsigned char ucMysticalShopId;
    int iRet = _stRoleToShopId.GetMysticalShopId(sPlayerLevel, ucMysticalShopId);
    CHECK_RETURN(iRet);

    CMysticalShopConfigUnit stConfigData;
    iRet = _stMystShopConfig.GetConfigData(ucMysticalShopId, stConfigData);
    CHECK_RETURN(iRet);

    unsigned char ucPos;
    stUserShop._stMysticalShop._astShopItem.Clear();
    for (int i = 0; i < MAX_MYSTICAL_SHOP_GRID_NUM; i++)
    {
        CDropItemData stDropItem;
        bool bHasSameItem = true;
        do
        {
            iRet = _stMystShopConfig._stMystItemDrop.DropShopItem(ucMysticalShopId, ucUpdateType, ucPos);
            if (iRet)
            {
                CT_ERROR(("Mystical shop drop item, usPlayerLevel: %u, ucUpdateType: %u, iRet: %u.", sPlayerLevel, ucUpdateType, iRet));
                return iRet;
            }

            CMysticalShopItemConfig stItemCfg;
            iRet = stConfigData.GetShopItem(ucPos, stItemCfg);
            if (iRet)
            {
                CT_ERROR(("%u, %d, %d.", ucMysticalShopId, ucPos, iRet));
                return iRet;
            }

            if (0 == stItemCfg._usConfigId)
            {
                iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetDropItemData(uiGid, stItemCfg._ucShopItemType, 0, stItemCfg._szShopItemSubType.Get(),
                    COMM_MOD, stItemCfg._ucShopCount, stDropItem);
                if (iRet)
                {
                    CT_ERROR(("%u, %d, %s, %d.", ucMysticalShopId, ucPos, stItemCfg._szShopItemSubType.Get(), iRet));
                    return iRet;
                }
            }
            else
            {
                stDropItem._ucItemType = stItemCfg._ucShopItemType;
                stDropItem._usItemConfigID = stItemCfg._usConfigId;
                stDropItem._iItemCount = stItemCfg._ucShopCount;
            }

            bHasSameItem = stUserShop._stMysticalShop.HasSameItem(stDropItem);
        } while (bHasSameItem);

        int iSilverPrices;
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetItemPrice(stDropItem._ucItemType, stDropItem._usItemConfigID,
            (unsigned short)stDropItem._iItemCount, ITEM_BUY_PRICE_SILVER, iSilverPrices);
        if (iRet)
        {
            CT_ERROR(("%u, %d, %d, %d.", ucMysticalShopId, ucPos, stDropItem._ucItemType, stDropItem._usItemConfigID));
            return iRet;
        }

        CShopItemConfig stShopItem;
        stShopItem._ucItemType = stDropItem._ucItemType;
        stShopItem._usItemConfigID = stDropItem._usItemConfigID;
        stShopItem._usItemCount = (unsigned short)stDropItem._iItemCount;
        stShopItem._ucBuyType = ITEM_TYPE_SILVER;
        stShopItem._ucExchangeItemType  = ITEM_TYPE_SILVER;
        stShopItem._usExchangeItemID      = 0;
        stShopItem._iExchangeItemCount = iSilverPrices;
        stUserShop._stMysticalShop._astShopItem.AddOneItem(stShopItem);

        CT_TRACE(("gid (%u), item_type: %d, item_id : %d, count: %d", uiGid, stShopItem._ucItemType, stShopItem._usItemConfigID, stShopItem._usItemCount));
    }

    return 0;
}

int CShopMgr::GetShopItem (short sRoleLevel, unsigned char ucShopType, unsigned short usPos,
                           CUserShop & stUserShop, CShopItemConfig& stConfigData)
{
    int iRet = 0;
    stConfigData.Clear();
    switch (ucShopType)
    {
    case SHOP_TYPE_NEARBY:
        {
            unsigned char ucNearByShopId;
            iRet = _stRoleToShopId.GetNearbyShopId(sRoleLevel, ucNearByShopId);
            CHECK_RETURN(iRet);

            iRet = _stNearByShopConfig.GetConfigData(ucNearByShopId, usPos, stConfigData);
            CHECK_RETURN(iRet);

            break;
        }
    case SHOP_TYPE_BUYBACK:
        {
            CShopBuyBackItem stBuyBackItem;
            iRet = GetBuyBackInfo(stUserShop, usPos, stBuyBackItem);
            CHECK_RETURN(iRet);

            stConfigData._ucItemType = stBuyBackItem._ucItemType;
            stConfigData._usItemConfigID = stBuyBackItem._uiItemConfigId;
            stConfigData._usItemCount = stBuyBackItem._usItemCount;
            stConfigData._ucBuyType = ITEM_TYPE_SILVER;
            stConfigData._usDiscount = 1000;
            stConfigData._iExchangeItemCount = (int)stBuyBackItem._uiPrice;
            break;
        }
    case SHOP_TYPE_MYSTICAL:
        {
            iRet = stUserShop._stMysticalShop.GetShopItem(usPos, stConfigData);
            CHECK_RETURN(iRet);
            break;
        }
    case SHOP_TYPE_EQUIP:
        {
            iRet = _stEquipShopConfig.GetConfigData(usPos, stConfigData);
            break;
        }

    case SHOP_TYPE_CLAN:
        {
            CClanEntry stClanEntry;
            iRet = CMainCtrl::m_pstMain->m_stClanMgr.GetClanEntry(stUserShop._stClanShop._uiClanId, stClanEntry);
            if (iRet)
            {
                CT_ERROR(("%d,%d", stUserShop._stClanShop._uiClanId, iRet));
                return iRet;
            }

            for (int i = 0; i < stUserShop._stClanShop._astBuyItems.Size(); i++)
            {
                if (usPos == stUserShop._stClanShop._astBuyItems[i])
                {
                    stConfigData._usExchangeItemID = SHOP_ITEM_SALE_OUT;
                    return 0;
                }
            }

            iRet = stClanEntry._stClanShop.GetShopItem(usPos, stConfigData);
            if (iRet)
            {
                CT_ERROR(("%d,%d", stUserShop._stClanShop._uiClanId, usPos));
                return iRet;
            }

            break;
        }

    case SHOP_TYPE_CRYSTAL:
        {
            for (int i = 0; i < stUserShop._astCrystalItems.Size(); i++)
            {
                if (usPos == stUserShop._astCrystalItems[i])
                {
                    stConfigData._usExchangeItemID = SHOP_ITEM_SALE_OUT;
                    return 0;
                }
            }

            CCrystalShopItemConfig stItemConfig;
            iRet = _stCrystalShopConfig.GetConfigData(usPos, stItemConfig);
            if (iRet)
            {
                CT_ERROR(("%d,%d", usPos, iRet));
                return iRet;
            }

            stConfigData._ucItemType = stItemConfig._ucItemType;
            stConfigData._usItemConfigID = stItemConfig._usItemId;
            stConfigData._usItemCount = (unsigned short)stItemConfig._iItemCount;
            stConfigData._ucBuyType = ITEM_TYPE_GOLD;
            stConfigData._iExchangeItemCount = (int)stItemConfig._iGoldCost;

            stConfigData._usDiscount = (unsigned short)stItemConfig._iSealCost;  //宝石商店.没有折扣,保存所需的印符
        }
        break;

    default:
        return ERROR_UNSUPPORT_SHOP_TYPE;
    }

    return 0;
}

int CShopMgr::GetNearByShopConfig (short sRoleLevel, unsigned short usPos, CShopItemConfig& stConfigData)
{
    int iRet = 0;
    unsigned char ucNearByShopId;
    iRet = _stRoleToShopId.GetNearbyShopId(sRoleLevel, ucNearByShopId);
    CHECK_RETURN(iRet);

    iRet = _stNearByShopConfig.GetConfigData(ucNearByShopId, usPos, stConfigData);
    CHECK_RETURN(iRet);

    return iRet;
}

void CShopMgr::SendInfoToFront (short sRoleLevel, CUserShop & stUserShop, unsigned char ucShopType, PBMsgHead stMsgHead, CEnpNetHead & stEnpHead)
{
    MsgAnsShopInfo stAns;

    GetShopInfo(sRoleLevel, stUserShop, ucShopType, stAns);

    stMsgHead.set_msgid(ID_MAIN_SHOP_GET_INFO);
    stMsgHead.set_msgact(0);
    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stAns, CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->AnswerToClient(stEnpHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
}

int CShopMgr::GetBuyPrice(short sRoleLevel, CUserShop& stUserShop, unsigned char ucShopType, unsigned short usPos, unsigned int& uiGoldPrice, unsigned int& uiSilverPrice)
{
    int iRet = 0;
    CShopItemConfig stShopConfigData;

    switch(ucShopType)
    {
    case CShopMgr::SHOP_TYPE_NEARBY:
        {
            unsigned char ucNearByShopId;
            iRet = _stRoleToShopId.GetNearbyShopId(sRoleLevel, ucNearByShopId);
            CHECK_RETURN(iRet);

            iRet = GetNearByShopConfig(ucNearByShopId, usPos, stShopConfigData);
            CHECK_RETURN(iRet);

            uiGoldPrice = (unsigned int)stShopConfigData._iExchangeItemCount;

            if (stShopConfigData._usItemCount == 0)
            {
                return ERROR_SHOP_NO_SELL_ITEM;
            }
        }
        break;
    case CShopMgr::SHOP_TYPE_BUYBACK:
        {
            CShopBuyBackItem stBuyBackItem;

            iRet = GetBuyBackInfo(stUserShop, usPos, stBuyBackItem);
            CHECK_RETURN(iRet);

            uiGoldPrice = 0;
            uiSilverPrice = stBuyBackItem._uiPrice;
            return 0;
        }
        break;
    case CShopMgr::SHOP_TYPE_MYSTICAL:
        {
            iRet = stUserShop._stMysticalShop.GetShopItem(usPos, stShopConfigData);
            CHECK_RETURN(iRet);
        }
        break;
    default:
        return ERROR_UNSUPPORT_SHOP_TYPE;
    }

    return 0;
}

int CShopMgr::AddBuyBackItem(CUserShop & stUserShop, CShopBuyBackItem & stBuyBackItem, CPlayerOnlineData& stPlayerOnlineData)
{
    if (stBuyBackItem._usItemCount <= 0)
    {
        return 0;
    }

    return stUserShop.AddBuyBackItem(stBuyBackItem);
}

int CShopMgr::TakeoutBuyBackItem(CUserShop & stUserShop, unsigned short usPos, CShopBuyBackItem& stBuyBackItem)
{
    return stUserShop.TakeoutBuyBackItem(usPos, stBuyBackItem);
}

//发送回购物品列表
void CShopMgr::SendBuyBackItemList(CUserShop& stUserShop, PBMsgHead stMsgHead, CEnpNetHead stEnpHead)
{
    MsgAnsShopInfo stAns;

    stMsgHead.set_msgret(RET_OK);
    stMsgHead.set_msgid(ID_MAIN_SHOP_GET_INFO);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    stAns.set_shop_type(SHOP_TYPE_BUYBACK);

    GetBuyBackList(stUserShop, stAns);

    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stAns, CMainCtrl::m_pstMain->m_stEncodeBuf);

    CMainCtrl::m_pstMain->AnswerToClient(stEnpHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
}

int CShopMgr::GetBuyBackInfo(CUserShop& stUserShop, unsigned short usPos, CShopBuyBackItem& stBuyBackItem)
{
    return stUserShop.GetBuyBackInfo(usPos, stBuyBackItem);
}

void CShopMgr::UpdateHistory (CShopHistoryItemData & stHistoryItem)
{
    CShopZoneData & stShopZoneData = CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stShopZoneData;

    stShopZoneData.AddHistoryItem(stHistoryItem);

    CVarObjectKey stKey;
    stKey.m_chDataType = DT_ZONE_DATA;
    stKey.m_u64ID = CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._uiZoneID;
    CMainCtrl::m_pstMain->UpdateData(stKey, CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData, VOP_UPDATE);
}

//获取商店内容
int CShopMgr::GetShopInfo (short sRoleLevel, CUserShop & stUserShop, unsigned char ucShopType, MsgAnsShopInfo & stAns)
{
    int iRet;
    T_SHOP_ITEM_LIST stItemList;

    stAns.set_shop_type(ucShopType);
    switch (ucShopType)
    {
    case SHOP_TYPE_NEARBY:
        {
            unsigned char ucNearByShopId;
            iRet = _stRoleToShopId.GetNearbyShopId(sRoleLevel, ucNearByShopId);
            CHECK_RETURN(iRet);

            iRet = _stNearByShopConfig.GetConfigData(ucNearByShopId, stItemList);
        }
        break;

    case SHOP_TYPE_BUYBACK:
        {
            iRet = GetBuyBackList(stUserShop, stAns);
        }
        break;

    case SHOP_TYPE_MYSTICAL:
        {
            int iNow = CMainCtrl::m_pstMain->m_iNow;
            int iCaneCDTime = 0;
            iRet = _stRoleToShopId.GetCaneCdTime(sRoleLevel, iCaneCDTime);
            if (iRet || iCaneCDTime <= 0)
            {
                CT_ERROR (("%d, %d, %d", iRet, sRoleLevel, iCaneCDTime));
                return iRet;
            }

            stUserShop._stMysticalShop.RenewCaneNum (iCaneCDTime, iNow);
            stAns.set_cane_num(stUserShop._stMysticalShop.GetCaneNum());
            stAns.set_cane_cd_time(stUserShop._stMysticalShop.GetCoolDownTime(iNow));
            stAns.set_refresh_need_gold(stUserShop._stMysticalShop.GetGoldRefreshCost());
#if 0
            CShopZoneData & stShopZoneData = CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stShopZoneData;
            for (int i = 0; i < stShopZoneData._astShopHistory.Size(); i++)
            {
                MsgShopHistoryItem * pstHistoryItem = stAns.add_shop_history();
                pstHistoryItem->set_gid(stShopZoneData._astShopHistory[i]._uiGid);
                int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stShopZoneData._astShopHistory[i]._uiGid);
                if (iIndex < 0)
                {
                    CT_WARNING(("Cann't find %u's baseinfo in hash.", stShopZoneData._astShopHistory[i]._uiGid));
                    continue;
                }

                pstHistoryItem->set_name(CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex]._sUserToken());
                pstHistoryItem->set_item_type(stShopZoneData._astShopHistory[i]._ucItemType);
                pstHistoryItem->set_item_id(stShopZoneData._astShopHistory[i]._usItemId);
            }
#endif
            iRet = stUserShop._stMysticalShop.GetShopIemList(stItemList);
        }
        break;

    case SHOP_TYPE_EQUIP:
        {
            iRet = _stEquipShopConfig.GetConfigData(stItemList);
        }
        break;

    case SHOP_TYPE_CLAN:
        {
            iRet = stUserShop.GetClanShopList(stItemList);
            stAns.set_refresh_cd_time(CTTimeUtils::GetDayBeginSec(CMainCtrl::m_pstMain->m_iNow) + 86400);
        }
        break;

    case SHOP_TYPE_CRYSTAL:
        {
            iRet = GetCrystalShopList(stUserShop, stAns);
        }
        break;

    default:
        return ERROR_UNSUPPORT_SHOP_TYPE;
    }

    if (RET_OK != iRet)
    {
        return iRet;
    }

    for (int i = 0; i < stItemList.Size(); ++i)
    {
        CShopItemConfig & stShopConfigData = stItemList[i];
        if (stShopConfigData._iExchangeItemCount <= 0 || stShopConfigData._usItemCount <= 0)
        {
            CT_ERROR(("%d, %d, %d, %d", ucShopType, i, stShopConfigData._ucItemType, stShopConfigData._usItemConfigID));
            continue;
        }

        MsgShopItem* pstMsgShopItem = stAns.add_items();

        MsgGridItemInfo stShopItemInfo;
        stShopItemInfo.set_item_store_pos(i);
        stShopItemInfo.set_item_type(stShopConfigData._ucItemType);
        stShopItemInfo.set_item_config_id(stShopConfigData._usItemConfigID);
        stShopItemInfo.set_item_count(stShopConfigData._usItemCount);

        *(pstMsgShopItem->mutable_item()) = stShopItemInfo;

        MsgResTriple * pstResTriple = pstMsgShopItem->add_cost();
        pstResTriple->set_res_type(stShopConfigData._ucBuyType);
        pstResTriple->set_res_cfg_id(stShopConfigData._usExchangeItemID);
        pstResTriple->set_res_value(stShopConfigData._iExchangeItemCount/stShopConfigData._usItemCount);  //前台要求返回物品的单价

        if (SHOP_ITEM_SALE_OUT == stShopConfigData._usExchangeItemID)
        {
            pstMsgShopItem->set_onsale_cnt(0);
        }
        else
        {
            pstMsgShopItem->set_onsale_cnt(stShopConfigData._usItemCount);
        }
    }

    return 0;
}

int CShopMgr::GetBuyBackList(CUserShop& stUserShop, MsgAnsShopInfo & stAns)
{
    for (int i = 0; i < stUserShop._astBuyBackItems.Size(); ++i)
    {
        CShopBuyBackItem& stBuyBackItem = stUserShop._astBuyBackItems[i];

        MsgShopItem* pstMsgShopItem = stAns.add_items();

        MsgGridItemInfo* pstGridItemInfo = pstMsgShopItem->mutable_item();

        CStorageGrid stGrid;
        stGrid._stKey._ucItemType = stBuyBackItem._ucItemType;
        stGrid._stKey._uiItemID = stBuyBackItem._uiItemID;
        stGrid._stKey._usStorePos = i;
        stGrid._shCount = (short)stBuyBackItem._usItemCount;
        stGrid._iInvalidTime = stBuyBackItem._iInvalidTime;

        CMainCtrl::m_pstMain->m_stStorageMgr.GetGridInfo(stUserShop._uiGid, stGrid, *pstGridItemInfo);

        MsgResTriple* pstResTriple = pstMsgShopItem->add_cost();
        pstResTriple->set_res_type(ITEM_TYPE_SILVER);      //回购只会使用银币
        pstResTriple->set_res_cfg_id(0);
        pstResTriple->set_res_value((stBuyBackItem._uiPrice/stBuyBackItem._usItemCount));   //前台要求返回物品的单价
    }

    return 0;
}

int CShopMgr::GetCrystalShopList(CUserShop& stUserShop, MsgAnsShopInfo & stAns)
{
    //判断活动是否打开
    if (!CMainCtrl::m_pstMain->m_stActMgr.IsActOpen(ACT_ID_WEEKEND_SHOP))
    {
        CT_WARNING(("crystal shop isn't open. %d", CMainCtrl::m_pstMain->m_iNow));
        return ERROR_SYS_NOT_OPEN;
    }

    for (int i = 0; i < _stCrystalShopConfig._astConfig.Size(); ++i)
    {
        CCrystalShopItemConfig & stShopItem = _stCrystalShopConfig._astConfig[i];
        MsgShopItem* pstMsgShopItem = stAns.add_items();

        MsgGridItemInfo* pstGridItemInfo = pstMsgShopItem->mutable_item();
        pstGridItemInfo->set_item_store_pos(i);
        pstGridItemInfo->set_item_type(stShopItem._ucItemType);
        pstGridItemInfo->set_item_config_id(stShopItem._usItemId);
        pstGridItemInfo->set_item_count(stShopItem._iItemCount);

        pstMsgShopItem->set_onsale_cnt (stShopItem._iItemCount);

        MsgResTriple* pstResTriple = pstMsgShopItem->add_cost();
        pstResTriple->set_res_type(ITEM_TYPE_GOLD);
        pstResTriple->set_res_cfg_id(0);
        pstResTriple->set_res_value(stShopItem._iGoldCost);   //返回物品总价

        pstResTriple = pstMsgShopItem->add_cost();
        pstResTriple->set_res_type(ITEM_TYPE_SEAL);
        pstResTriple->set_res_cfg_id(1);
        pstResTriple->set_res_value(stShopItem._iSealCost);   //返回物品总价

        for (int k = 0; k < stUserShop._astCrystalItems.Size(); k++)
        {
            if (i == stUserShop._astCrystalItems[k])
            {
                pstMsgShopItem->set_onsale_cnt (0);
            }
        }
    }

    return 0;
}

int CShopMgr::GetCanCdTime (unsigned int uiGid, int & iCDTime)
{
    iCDTime = 86400;

    short shLevel = 0;
    int iRet = CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleLevel(uiGid, shLevel);
    if (iRet)
    {
        CT_ERROR (("%d, %d", iRet, uiGid));
        return iRet;
    }

    iRet = _stRoleToShopId.GetCaneCdTime(shLevel, iCDTime);
    if (iRet || iCDTime <= 0)
    {
        CT_ERROR (("%d, %d, %d", iRet, uiGid, shLevel));
        return ERROR_SHOP_CONFIGID_ERR;
    }

    return 0;
}

int CShopMgr::DeliverGoods (CPlayerOnlineData & stPlayerOnlineData, CPlayerBaseInfo & stPlayerBaseInfo, CPlayerDetailInfo & stPlayerDetailInfo,
                            CPlayerDetailInfoEx1 & stPlayerDetailInfoEx1, unsigned int uiGoodsId, int iCount, EN_DELIVER_GOODS_TYPE enType, CDropItem & stDropItem)

{
    CMainCtrl * pstMainCtrl = CMainCtrl::m_pstMain;
    int iRet = RET_OK;
    unsigned int uiGID = stPlayerDetailInfoEx1._uiGID;

    stDropItem.Clear();

    bool bIsLimitedGoods = pstMainCtrl->m_stQQMallMgr.IsLimitGoods(uiGoodsId);
    if (bIsLimitedGoods)
    {
        iRet = pstMainCtrl->m_stQQMallMgr.AddBuyedLimitGoods (stPlayerDetailInfoEx1, uiGoodsId, iCount, pstMainCtrl->m_iNow);
        CT_TRACE(("%d, %d, %d, %d, %d", uiGID, uiGoodsId, iCount, pstMainCtrl->m_iNow, iRet));
        if (iRet)
        {
            return 4;
        }
    }

    iRet = pstMainCtrl->m_stQQMallMgr.GetMallDropGoods(uiGoodsId, iCount, stDropItem);
    if (iRet)
    {
        //CT_ERROR(("open id = %s, billno = %s, content = %s, ret = %d",
        //  stPara.GetValue("openid"), stPara.GetValue("billno"), stPara.GetValue("payitem"), iRet));

        //stAns.msg.Set("购买的商品ID %u 错误", uiGoodsId);
        return 5;
    }

    if (DELIVER_GOODS_QQ == enType)
    {
        stDropItem.SetOssModule(OSS_MODULE_QQ_PAY);
    }
    else if (DELIVER_GOODS_OWN == enType)
    {
        stDropItem.SetOssModule(OSS_MODULE_MALL_OWN);
    }

    //发货
    iRet = pstMainCtrl->m_stItemMgr.DropItem(0, uiGID, stDropItem, true);
    if (iRet)
    {
        //stAns.msg.Set("背包剩余空间不足");
        return 6;
    }

    //小秘书任务触发
    const CMallGoodsUnit& stGoodsConfig = pstMainCtrl->m_stQQMallMgr.GetGoodUnit(uiGoodsId);
    if (stGoodsConfig._iDailyTaskTriggerType != 0)
    {
        pstMainCtrl->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, stGoodsConfig._iDailyTaskTriggerType,
            iCount * stGoodsConfig._iDailyTaskTriggerCount);
    }

    //触发金色坐骑的跑马灯
    if (ITEM_TYPE_MOUNT == stGoodsConfig._ucItemType)
    {
        char chColor = pstMainCtrl->m_stMountMgr._stMountCfg.GetColor(stGoodsConfig._usItemCfgId);        
        if (MOUNT_COLOR_GOLD == chColor)
        {
            MsgTips stTips;
            stTips.set_type(1079);
            stTips.add_tip_argument(CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(uiGID));
            stTips.add_tip_argument(CTStringUtils::IntToString(stGoodsConfig._usItemCfgId));
            
            CMainCtrl::m_pstMain->SendOnlineTips(stTips);
        }
    }
    

    //保存数据
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
    stKey.m_u64ID = stPlayerDetailInfo._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

    stKey.m_chDataType = DT_PLAYER_DETAIL_EX1_INFO;
    stKey.m_u64ID = stPlayerDetailInfoEx1._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerDetailInfoEx1, VOP_UPDATE);

    return RET_OK;
}
